<?php
/**
 * Esta clase se encarga de la gestión de los objetos guardados en la sesión.
 * El propósito es posibilitar al cliente a acceder a los objetos (y sus métodos) guardados,
 * de una forma sencilla y centralizar el manejo del array $_SESSION en una sola clase.
 * 
 * Funcionamiento:
 * Para cada objeto creado se autogenerará un id único que se usará como identificador
 * en el array $_SESSION['controllers'][ClassName][$id]. En cada llamada http, se debe especificar
 * el id si se quiere acceder al objeto creado, si no es especificado se creará un nuevo objeto,
 * se autogenerará un nuevo identificador y se guardará automaticamente para ser usado en posteriores
 * llamadas.
 * En otras palabras los obetos que deriven de esta clase tendrán la posibilidad de persistir a lo
 * largo de diferentes llamadas http de una sesión con un cliente.
 * 
 * @author marcelo
 *
 */
class Controller {
	
	// En este array se guardarán las referencias de los objetos que sean recogidos de la sesión por
	// primera vez, para que en las siguientes peticiones del objeto se devuelva la referencia
	// y no sea nuevamente deserializado de la sesión
	private static $controllers = array();
	
	protected static function isControllerSet($controllerName, $controllerId) {
		return Controller::isValidId($controllerId)
		    && !empty($_SESSION['controllers'][$controllerName][$controllerId]);
	}
	
	protected static function getController($controllerName, $controllerId) {
		$controller = Controller::$controllers[$controllerName][$controllerId];
		if (!isset($controller)) {
			$controller = unserialize($_SESSION['controllers'][$controllerName][$controllerId]);
			Controller::$controllers[$controllerName][$controllerId] = $controller;
		}
		return $controller;
	}
	
	public function newId($controllerName, $params) {
		$controller = new $controllerName($params);
		$id = $controller->getId();
		unset($controller);
		return $id;
	}
	
	public static function callMethod($controllerName, $controllerId, $method, $params) {
//		unset($_SESSION['controllers']);
//		die();
		try {
			if (is_subclass_of($controllerName, "Controller")) {
				$reflectionMethod = new ReflectionMethod($controllerName, $method);
				if ($reflectionMethod->isPublic()) {
					if ($reflectionMethod->isStatic()) {
						$function = $controllerName."::".$method;
						if ( is_callable($function, $params) ) {
							call_user_func($function, $params);
						}
					} else {
						if (Controller::isControllerSet($controllerName, $controllerId)) {
							$controller = Controller::getController($controllerName, $controllerId);
						} else {
							$controller = new $controllerName($params);
						}
						
						if ( is_callable(array($controller, $method)) ) {
							call_user_func(array($controller, $method), $params);
						}
					}
				}
			} else {
				throw new Exception("Controller::callMethod(): controllerName: $controllerName is not sub class of Controller.");
			}
		} catch (Exception $e) {
			$view = new View('com/code/exception/ExceptionView.php');
			$vars = array();
//			$view->display($vars);
			echo $e->getMessage();
//			if (Controller::isControllerSet($controllerName, $controllerId)) {
//				$controller = Controller::getController($controllerName, $controllerId);
//				$controller->sessionDelete();
//			}
		}
	}
	
	public static function ping() {
		echo '({"ping" : "ok"})';
	}
	
	public static function isValidId($id) {
		$valid = strlen($id) == (32 + 2);
		$valid = $valid && preg_match('/[abcdefABCDEF|0123456789]+/i', $id, $matches, PREG_OFFSET_CAPTURE, 2);
		$valid = $valid && "ID".$matches[0][0] == $id;
		return $valid;
	}

	protected $id;
	private $deleted = false;

	public function __construct($params) {
		$id = $params['id'];
		if (empty($id)) {
			$this->id = "ID".md5(uniqid());
		} else {
			// throw new Exception();
		}
	}
	
	public function __destruct() {
		if (!$this->deleted()) {
			$this->sessionSave();
		}
	}
	
	public static function getUri() {
		$protocol = ($_SERVER['HTTPS'] == "on" ? "https" : "http");
		return "$protocol://".$_SERVER['SERVER_NAME']."/api.php";
	}

	public function getName() {
		return get_class($this);
	}

	public function getId() {
		return $this->id;
	}
	
	public function deleted() {
		return $this->deleted;
	}

	protected function sessionSave() {
		$this->deleted = false;
		$controllerName = $this->getName();
		$controllerId   = $this->getId();
		$_SESSION['controllers'][$controllerName][$controllerId] = serialize($this);
	}
	
	protected function sessionDelete() {
		$this->deleted = true;
		$controllerName = $this->getName();
		$controllerId   = $this->getId();
		unset($_SESSION['controllers'][$controllerName][$controllerId]);
	}
	
	public function redirectAgentTo($method) {
		$redirectionString = Controller::getUri()."?controller=".$this->getName()."&do=".$method."&id=".$this->getId();

		header("HTTP/1.1 302 Moved Temporarily");
		header("Location: $redirectionString");
	}
	
	public function getControllerIdentifier() {
		$id = array();
		$id['uri'] = Controller::getUri();
		$id['name'] = $this->getName();
		$id['id'] = $this->getId();
		
		return $id;
	}
}
?>